import * as Cesium from 'cesium'

import CreatePolygon from './CreatePolygon'

export default function initExcavationTool(viewer, options) {

  let excavateMinHeight = 9999

  let wallData = {}

  let bottomSurface = undefined

  let wellWall = undefined

  this.startCreate = function startCreate() {

    //绘制任意多边形

    CreatePolygon(
      viewer,

      {

        color: Cesium.Color.RED.withAlpha(0.1),

        outlineColor: Cesium.Color.YELLOW,

        outlineWidth: 2

      },

      function (polygon) {

        const points = polygon.pottingPoint

        viewer.entities.remove(polygon)

        //将获取到的坐标点进行下一步的地形剖切

        updateData(points)

      }
    )

    return

  }

  function updateData(points) {

    //剖切之前将所有面清除

    clear()

    let clippingPlanesList = []

    //计算两个笛卡尔函数的分量差异

    let car3Difference = Cesium.Cartesian3.subtract(points[0], points[1], new Cesium.Cartesian3())

    for (let index = 0; index < points.length; ++index) {

      let s = (index + 1) % points.length

      let cartographic = Cesium.Cartographic.fromCartesian(points[index])

      let curHeight = cartographic.height

      if (curHeight < excavateMinHeight) {

        excavateMinHeight = curHeight

      }

      //计算中间点

      let curMidPoint = Cesium.Cartesian3.midpoint(points[index], points[s], new Cesium.Cartesian3())

      curMidPoint = Cesium.Cartesian3.multiplyByScalar(curMidPoint, 0.5, curMidPoint)

      //中间点标准化

      let curMidPointNormal = Cesium.Cartesian3.normalize(curMidPoint, new Cesium.Cartesian3())

      //相邻向量相减

      let curMidPointDifference = Cesium.Cartesian3.subtract(points[s], curMidPoint, new Cesium.Cartesian3())

      curMidPointDifference = Cesium.Cartesian3.normalize(curMidPointDifference, curMidPointDifference)

      //叉乘

      let curMidPointCross = Cesium.Cartesian3.cross(curMidPointDifference, curMidPointNormal, new Cesium.Cartesian3())

      curMidPointCross = Cesium.Cartesian3.normalize(curMidPointCross, curMidPointCross)

      let plane = new Cesium.Plane(curMidPointCross, 0)

      let distance = Cesium.Plane.getPointDistance(plane, curMidPoint)

      clippingPlanesList.push(new Cesium.ClippingPlane(curMidPointCross, distance))

    }

    viewer.scene.globe.clippingPlanes = new Cesium.ClippingPlaneCollection({

      planes: clippingPlanesList,

      edgeWidth: 1,

      edgeColor: Cesium.Color.WHITE,

      enabled: true

    })

    prepareWell(points)

    createWell(wallData)

  }

  function clear() {

    if (viewer.scene.globe.clippingPlanes) {

      viewer.scene.globe.clippingPlanes.enabled = false

      viewer.scene.globe.clippingPlanes.removeAll()

      viewer.scene.globe.clippingPlanes = undefined

    }

    if (bottomSurface) {

      viewer.scene.primitives.remove(bottomSurface)

      bottomSurface = undefined

    }

    if (wellWall) {

      viewer.scene.primitives.remove(wellWall)

      wellWall = undefined

    }

    viewer.scene.render()

  }

  //计算并更新wallData

  function prepareWell(points) {

    let pointLength = points.length

    let heightDiff = excavateMinHeight - options.height

    let no_height_top = [],

      bottom_pos = [],

      lerp_pos = []

    for (let m = 0; m < pointLength; m++) {

      let n = m == pointLength - 1 ? 0 : m + 1

      let point0 = [Cesium.Cartographic.fromCartesian(points[m]).longitude, Cesium.Cartographic.fromCartesian(points[m]).latitude]

      let point1 = [Cesium.Cartographic.fromCartesian(points[n]).longitude, Cesium.Cartographic.fromCartesian(points[n]).latitude]

      if (0 == m) {

        lerp_pos.push(new Cesium.Cartographic(point0[0], point0[1]))

        bottom_pos.push(Cesium.Cartesian3.fromRadians(point0[0], point0[1], heightDiff))

        no_height_top.push(Cesium.Cartesian3.fromRadians(point0[0], point0[1], 0))

      }

      for (let p = 1; p <= options.splitNum; p++) {

        let o = Cesium.Math.lerp(point0[0], point1[0], p / options.splitNum)

        let g = Cesium.Math.lerp(point0[1], point1[1], p / options.splitNum)

        ;(m == pointLength - 1 && p == options.splitNum) ||

        (lerp_pos.push(new Cesium.Cartographic(o, g)),

          bottom_pos.push(Cesium.Cartesian3.fromRadians(o, g, heightDiff)),

          no_height_top.push(Cesium.Cartesian3.fromRadians(o, g, 0)))

      }

    }

    wallData = {

      lerp_pos: lerp_pos, //地形坐标点包括高度

      bottom_pos: bottom_pos, //相对应的地底坐标点

      no_height_top: no_height_top //地形坐标点不包括高度

    }

  }

  //开始创建底面和侧面

  function createWell(wallData) {

    if (viewer.terrainProvider._layers) {

      //创建底面

      createBottomSurface(wallData.bottom_pos)

      //Cesium.sampleTerrainMostDetailed可以获取地形点所对应的精确地形高度

      Cesium.sampleTerrainMostDetailed(viewer.terrainProvider, wallData.lerp_pos).then(function (pos) {

        let positionList = []

        for (let index = 0; index < pos.length; index++) {

          const element = pos[index]

          let curPos = Cesium.Cartesian3.fromRadians(element.longitude, element.latitude, element.height)

          //所有地形点

          positionList.push(curPos)

        }

        //创建侧面对象

        createWellWall(wallData.bottom_pos, positionList)

      })

    } else {

      createBottomSurface(wallData.bottom_pos)

      createWellWall(wallData.bottom_pos, wallData.no_height_top)

    }

  }

  //坐标转换，转出经纬度格式

  function ellipsoidToDegree(position) {

    let cartesian3 = new Cesium.Cartesian3(position.x, position.y, position.z)

    let cartographic = viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian3)

    return {

      longitude: Cesium.Math.toDegrees(cartographic.longitude),

      latitude: Cesium.Math.toDegrees(cartographic.latitude),

      altitude: cartographic.height

    }

  }

  //创建地形开挖的底面对象

  function createBottomSurface(points) {

    if (points.length) {

      let minHeight = getMinHeight(points)

      let positions = []

      for (let i = 0; i < points.length; i++) {

        let curPoint = ellipsoidToDegree(points[i])

        positions.push(curPoint.longitude, curPoint.latitude, minHeight)

      }

      let polygon = new Cesium.PolygonGeometry({

        polygonHierarchy: new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArrayHeights(positions)),

        perPositionHeight: true

      })

      let material = new Cesium.Material({

        fabric: {

          type: 'Image',

          uniforms: {

            image: options.bottomImg

          }

        }

      })

      let appearance = new Cesium.MaterialAppearance({

        translucent: false,

        flat: true,

        material: material

      })

      bottomSurface = new Cesium.Primitive({

        geometryInstances: new Cesium.GeometryInstance({

          geometry: Cesium.PolygonGeometry.createGeometry(polygon)

        }),

        appearance: appearance,

        asynchronous: false

      })

      viewer.scene.primitives.add(bottomSurface)

    }

  }

  //创建地形开挖的侧面墙对象

  function createWellWall(bottomPos, positionList) {

    let minHeight = getMinHeight(bottomPos)

    let maxHeights = [],

      minHeights = []

    for (let i = 0; i < positionList.length; i++) {

      maxHeights.push(ellipsoidToDegree(positionList[i]).altitude)

      minHeights.push(minHeight)

    }

    let wall = new Cesium.WallGeometry({

      positions: positionList,

      maximumHeights: maxHeights,

      minimumHeights: minHeights

    })

    let geometry = Cesium.WallGeometry.createGeometry(wall)

    let material = new Cesium.Material({

      fabric: {

        type: 'DiffuseMap',

        uniforms: {

          image: options.wallImg,

          repeat: new Cesium.Cartesian2(1, 1)

        }

      }

    })

    let appearance = new Cesium.MaterialAppearance({

      translucent: false,

      flat: true,

      material: material

    })

    wellWall = new Cesium.Primitive({

      geometryInstances: new Cesium.GeometryInstance({

        geometry: geometry

      }),

      appearance: appearance,

      asynchronous: false

    })

    viewer.scene.primitives.add(wellWall)

  }

  //获取地形开挖最低点高程值

  function getMinHeight(points) {

    let minHeight = 5000000

    let minPoint = null

    for (let i = 0; i < points.length; i++) {

      let height = points[i]['z']

      if (height < minHeight) {

        minHeight = height

        minPoint = ellipsoidToDegree(points[i])

      }

    }

    return minPoint.altitude

  }

  this.switchExcavate = function (show) {

    if (show) {

      viewer.scene.globe.material = null

      wellWall.show = true

      bottomSurface.show = true

    } else {

      viewer.scene.globe.material = null

      wellWall.show = false

      bottomSurface.show = false

    }

  }

  //挖掘深度变化

  this.updateExcavateDepth = function (height) {

    viewer.scene.primitives.remove(bottomSurface)

    viewer.scene.primitives.remove(wellWall)

    let lerp_pos = wallData.lerp_pos

    let posList = []

    for (let n = 0; n < lerp_pos.length; n++) {

      posList.push(Cesium.Cartesian3.fromRadians(lerp_pos[n].longitude, lerp_pos[n].latitude, excavateMinHeight - height))

    }

    wallData.bottom_pos = posList

    createWell(wallData)

  }

}
